priority -50
# notes based on https://wangdoc.com/bash/
# note based on https://github.com/dylanaraps/pure-bash-note

snippet note_variable "variable"
# 如果 varname 不是"存在且不为空"
#   ${varname:-word} : 那么得到 word
#   ${varname:=word} : 那么得到 word，并且 varname=word
#   ${varname:?message} : 那么展示 message
# ${varname:+word} 和 - 反过来的
endsnippet

snippet note_here "heredoc"
# 如果不希望发生变量替换，可以把 Here 文档的开始标记放在单引号之中。
# << '_EOF_'
# text
# _EOF_

# 将 heredoc 导入到文档中
# cat << _EOF_ > /tmp/yourfile
# text
# _EOF_

# 此外 here string
# $ cat <<< 'hi there'
# 等同于
# $ echo 'hi there' | cat
endsnippet

snippet note_case "switch case"
case "$action" in
a | b)
  echo for a or b
  ;;&
b | c)
  echo for c or b
  ;;&
a | b | c) ;;
*)
  echo for everything ELSE
  ;;
esac
endsnippet


snippet note_glob "C style for loop"
# ?(pattern-list)：匹配零个或一个模式。
# *(pattern-list)：匹配零个或多个模式。
# +(pattern-list)：匹配一个或多个模式。
# @(pattern-list)：只匹配一个模式。
# !(pattern-list)：匹配给定模式以外的任何内容。
#
# 比如匹配
# shopt -s extglob nullglob
# for i in rime/*.@(yaml|txt);do
#   echo $i
# done
endsnippet

snippet fori "C style for loop"
VAR=50
for ((i=0;i<=VAR;i=i + 4)); do
        printf '%s\n' "$i"
done
endsnippet

snippet note_getoption "参数选项"
function usage() {
  echo "Usage :   [options] [--]

    Options:
    -h|help       Display this message"
}

cmd=""
while getopts "hc:" opt; do
  case \$opt in
  c) cmd=\${OPTARG} ;;
  h)
    usage
    exit 0
    ;;
  *)
    echo -e "\n  Option does not exist : OPTARG\n"
    usage
    exit 1
    ;;
  esac # --- end of case ---
done
shift $((OPTIND - 1))
endsnippet

snippet note_readfile "read file line by line"
# https://stackoverflow.com/questions/10929453/read-a-file-line-by-line-assigning-the-value-to-a-variable
while read -r line; do
        read -ra array <<< "$line"
        for w in "${array[@]}"; do
                echo "[$w]"
        done
done <ByMyWill.md
endsnippet

snippet note_issubstr "is substring"
string='My long string'
if [[ $string == *"My long"* ]]; then
        echo "It's there!"
fi
endsnippet

snippet note_string_replace "string replace"
# 如果 pattern 匹配变量 variable 的开头，
# 删除最短匹配（非贪婪匹配）的部分，返回剩余部分
${variable#pattern}

# 如果 pattern 匹配变量 variable 的开头，
# 删除最长匹配（贪婪匹配）的部分，返回剩余部分
${variable##pattern}

# 如果 pattern 匹配变量 variable 的结尾，
# 删除最短匹配（非贪婪匹配）的部分，返回剩余部分
${variable%pattern}

# 如果 pattern 匹配变量 variable 的结尾，
# 删除最长匹配（贪婪匹配）的部分，返回剩余部分
${variable%%pattern}

# 如果 pattern 匹配变量 variable 的一部分，
# 最长匹配（贪婪匹配）的那部分被 string 替换，但仅替换第一个匹配
${variable/pattern/string}

# 如果 pattern 匹配变量 variable 的一部分，
# 最长匹配（贪婪匹配）的那部分被 string 替换，所有匹配都替换
${variable//pattern/string}

# 经典案例
# filename=$(basename -- "$fullfile")
# extension="${filename##*.}"
# filename="${filename%.*}"
endsnippet

snippet note_cmpbool "compare file"
the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
        echo 'Be careful not to fall off!'
fi

endsnippet

snippet note_cmpfile "compare file"
# https://wangdoc.com/bash/condition.html
# [ -a file ]：如果 file 存在，则为true。
# [ -b file ]：如果 file 存在并且是一个块（设备）文件，则为true。
# [ -c file ]：如果 file 存在并且是一个字符（设备）文件，则为true。
# [ -d file ]：如果 file 存在并且是一个目录，则为true。
# [ -e file ]：如果 file 存在，则为true。
# [ -f file ]：如果 file 存在并且是一个普通文件，则为true。
# [ -g file ]：如果 file 存在并且设置了组 ID，则为true。
# [ -G file ]：如果 file 存在并且属于有效的组 ID，则为true。
# [ -h file ]：如果 file 存在并且是符号链接，则为true。
# [ -k file ]：如果 file 存在并且设置了它的“sticky bit”，则为true。
# [ -L file ]：如果 file 存在并且是一个符号链接，则为true。
# [ -N file ]：如果 file 存在并且自上次读取后已被修改，则为true。
# [ -O file ]：如果 file 存在并且属于有效的用户 ID，则为true。
# [ -p file ]：如果 file 存在并且是一个命名管道，则为true。
# [ -r file ]：如果 file 存在并且可读（当前用户有可读权限），则为true。
# [ -s file ]：如果 file 存在且其长度大于零，则为true。
# [ -S file ]：如果 file 存在且是一个网络 socket，则为true。
# [ -t fd ]：如果 fd 是一个文件描述符，并且重定向到终端，则为true。 这可以用来判断是否重定向了标准输入／输出／错误。
# [ -u file ]：如果 file 存在并且设置了 setuid 位，则为true。
# [ -w file ]：如果 file 存在并且可写（当前用户拥有可写权限），则为true。
# [ -x file ]：如果 file 存在并且可执行（有效用户有执行／搜索权限），则为true。
# [ file1 -nt file2 ]：如果 FILE1 比 FILE2 的更新时间最近，或者 FILE1 存在而 FILE2 不存在，则为true。
# [ file1 -ot file2 ]：如果 FILE1 比 FILE2 的更新时间更旧，或者 FILE2 存在而 FILE1 不存在，则为true。
# [ FILE1 -ef FILE2 ]：如果 FILE1 和 FILE2 引用相同的设备和 inode 编号，则为true。
endsnippet

snippet note_cmpstring "compare string"
# [ string ]：如果string不为空（长度大于0），则判断为真。
# [ -n string ]：如果字符串string的长度大于零，则判断为真。
# [ -z string ]：如果字符串string的长度为零，则判断为真。
# [ string1 = string2 ]：如果string1和string2相同，则判断为真。
# [ string1 == string2 ] 等同于[ string1 = string2 ]。
# [ string1 != string2 ]：如果string1和string2不相同，则判断为真。
# [ string1 '>' string2 ]：如果按照字典顺序string1排列在string2之后，则判断为真。
# [ string1 '<' string2 ]：如果按照字典顺序string1排列在string2之前，则判断为真。
# [ string1 =~ string2 ]：判断 string2 是不是 string1 的 substring。
endsnippet

snippet note_cmpint "compare int"
# [ integer1 -eq integer2 ]：如果integer1等于integer2，则为true。
# [ integer1 -ne integer2 ]：如果integer1不等于integer2，则为true。
# [ integer1 -le integer2 ]：如果integer1小于或等于integer2，则为true。
# [ integer1 -lt integer2 ]：如果integer1小于integer2，则为true。
# [ integer1 -ge integer2 ]：如果integer1大于或等于integer2，则为true。
# [ integer1 -gt integer2 ]：如果integer1大于integer2，则为true。
endsnippet

snippet note_select "compare int"
select brand in Samsung Sony iphone symphony Walton
do
        echo "You have chosen $brand"
done
endsnippet

snippet note_forarray "for every element in array"
for i in "${array[@]}"; do
        echo "$i"
done
endsnippet

snippet note_forarrayindex "for every element in array"
for ((i=0;i<${#arr[@]};i++)); do
        printf '%s\n' "${arr[i]}"
done
endsnippet

snippet note_readintoarray "read into array"
array=()
read -r -a array
for i in "${array[@]}"; do
        echo "$i"
done
endsnippet

snippet note_trim_string "trim string"
# Usage: trim_string "   example   string    "
function trim_string() {
        : "${1#"${1%%[![:space:]]*}"}"
        : "${_%"${_##*[![:space:]]}"}"
        printf '%s\n' "$_"
}
endsnippet

snippet note_trim_all "trim all"
# shellcheck disable=SC2086,SC2048
# Usage: trim_all "   example   string    "
function trim_all() {
        set -f
        set -- $*
        printf '%s\n' "$*"
        set +f
}
endsnippet

snippet note_split "split"
# Usage: split "string" "delimiter"
function split() {
        IFS=$'\n' read -d "" -ra arr <<<"${1//$2/$'\n'}"
        printf '%s\n' "${arr[@]}"
}
endsnippet

snippet note_iter_dir "iter dir recursively"
shopt -s globstar
for file in "$(pwd)"/**; do
        printf '%s\n' "$file"
done
shopt -u globstar
endsnippet

snippet note_head "head lines of file"
# Usage: head "n" "file"
head() {
        mapfile -tn "$1" line <"$2"
        printf '%s\n' "${line[@]}"
}
endsnippet

snippet note_tail "tail lines of file"
tail() {
        # Usage: tail "n" "file"
        mapfile -tn 0 line < "$2"
        printf '%s\n' "${line[@]: -$1}"
}
endsnippet

snippet note_exits "tail lines of file"
function exits() {
  if ! [ -x "$(command -v $1)" ]; then
    echo "Error: $1 is not installed." >&2
    exit 1
  fi
}
endsnippet

snippet note_secure "make bash more secure"
# -u ：试图使用未定义的变量，就立即退出。
# -o pipefail ： 只要管道中的一个子命令失败，整个管道命令就失败。
set -E -e -u -o pipefail
endsnippet

snippet note_find "find checksheet"
# - find /tmp -size 0 -print0 -delete : 删除大小为 0 的文件
# - find 和 xargs 混合使用的时候，分别加上 -print0 和 -0
#   - find . -type f -print0 | xargs -0 md5sum
#   - https://www.shellcheck.net/wiki/SC2038
# - hash: find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
endsnippet

snippet note_sed "sed"
# sed -i '1i hello world;' a.sh # 在 a.sh 中的第一行的位置插入 hello world
endsnippet

snippet note_template "template"
#!/usr/bin/env bash

set -E -e -u -o pipefail
readonly PROGNAME=$(basename \$0)
readonly PROGDIR=$(readlink -m "$(dirname \$0)")
readonly ARGS="$@"
cd "$(dirname "\$0")"
endsnippet

snippet note_split_to_array "template"
# The shell scans the results of parameter expansion,
# command substitution, and arithmetic expansion
# that did not occur within double quotes for word splitting.
s='foo bar baz'
a=( $s ) # a=( "$s" )
echo ${a[0]}

# 正确的写法是:
var="a aba a a a "
IFS=" " read -r -a array <<< "$var"
echo ${array[0]}
endsnippet
